#pragma once

#include "../common/Base.h"
#include "../common/Dispatcher.h"
#include "../client/RpcClient.h"
#include "RpcRouter.h"
#include "RpcTopic.h"
#include "RpcRegister.h"

namespace rpc
{
    namespace server
    {

        // 注册中心服务端：只需要针对服务注册与发现请求进行处理即可
        class RegisterServer
        {
        public:
            using ptr = std::shared_ptr<RegisterServer>;

            RegisterServer(int port)
                : _dispatcher(std::make_shared<Dispatcher>()), _pdManager(std::make_shared<PDManager>())
            {
                _server = ServiceFactory::create(port);

                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE,
                                                             std::bind(&PDManager::onServiceRequest, _pdManager.get(), _1, _2));

                std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)> messageCb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), _1, _2);
                _server->setMessageCallback(messageCb);

                std::function<void(const BaseConnection::ptr &)> closeCb = std::bind(&RegisterServer::onConnShutdown, this, _1);
                _server->setCloseCallback(closeCb);
            }

            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _pdManager->onConnShutdown(conn);
            }

        private:
            PDManager::ptr _pdManager;
            Dispatcher::ptr _dispatcher;
            BaseService::ptr _server;
        };

        class RpcServer
        {
        public:
            using ptr = std::shared_ptr<RpcServer>;
            // rpc——server端有两套地址信息：
            //   1. rpc服务提供端地址信息--必须是rpc服务器对外访问地址（云服务器---监听地址和访问地址不同）
            //   2. 注册中心服务端地址信息 -- 启用服务注册后，连接注册中心进行服务注册用的
            RpcServer(const Address &accessHost, bool enableRegistry = false, const Address &regClient = Address())
                : _enableRegistry(enableRegistry), _access_addr(accessHost), _router(std::make_shared<RpcRouter>()), _dispatcher(std::make_shared<Dispatcher>())
            {
                // 如果允许当前服务提供服务
                if (_enableRegistry)
                {
                    _reg_client = std::make_shared<client::RegistryClient>(regClient.first, regClient.second);
                }

                auto rpcCb = std::bind(&RpcRouter::onRpcRequest, _router.get(), _1, _2);
                _dispatcher->registerHandler<RpcRequest>(MType::REQ_RPC, rpcCb);

                std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)> messageCb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), _1, _2);
                _server = ServiceFactory::create(accessHost.second);

                _server->setMessageCallback(messageCb);
            }

            void registerMethod(const ServiceDescribe::ptr &service)
            {
                if (_enableRegistry)
                {
                    _reg_client->registerMethod(service->method(), _access_addr);
                }
                _router->registerMethod(service);
            }

            void start()
            {
                _server->start();
            }

        private:
            bool _enableRegistry;
            Address _access_addr;
            client::RegistryClient::ptr _reg_client;
            RpcRouter::ptr _router;
            BaseService::ptr _server;
            Dispatcher::ptr _dispatcher;
        };

        class TopicServer
        {
        public:
            using ptr = std::shared_ptr<TopicServer>;

            TopicServer(int port)
                : _dispatcher(std::make_shared<Dispatcher>()), _topicManager(std::make_shared<TopicManager>())
            {
                _server = ServiceFactory::create(port);

                auto topicCb = std::bind(&TopicManager::onTopicRequest, _topicManager.get(), _1, _2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, topicCb);

                // Becareful
                std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)> messageCb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), _1, _2);
                _server->setMessageCallback(messageCb);

                std::function<void(const BaseConnection::ptr &)> closeCb = std::bind(&TopicServer::onConnShutdown, this, _1);
                _server->setCloseCallback(closeCb);
            }

            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _topicManager->onShutdown(conn);
            }

        private:
            Dispatcher::ptr _dispatcher;
            TopicManager::ptr _topicManager;
            BaseService::ptr _server;
        };

    }; // SERVER
}; // RPC